package jmine.tec.utils.reflection.fast;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Collection;

/**
 * Representa um acessor para uma classe. Serve com pequeno wrapper sobre reflection para poder usar implementacoes melhores.
 * 
 * @author takeshi
 */
public interface FastClass {

    /**
     * Devolve todos os construtores declarados pela classe
     * 
     * @return {@link Collection} of {@link FastConstructor}
     */
    Collection<? extends FastConstructor> getConstructors();

    /**
     * Devolve o construtor com os argumentos dos tipo passados ou <code>null</code> se nenhum for encontrado
     * 
     * @param types array de {@link Class}
     * @return {@link FastConstructor}
     */
    FastConstructor findConstructor(Class<?>... types);

    /**
     * Devolve o construtor equivalente ao {@link Constructor} passado
     * 
     * @param ctor {@link Constructor}
     * @return {@link FastConstructor}
     */
    FastConstructor findConstructor(Constructor<?> ctor);

    /**
     * O tipo
     * 
     * @return {@link Class}
     */
    Class<?> getType();

    /**
     * Devolve os {@link FastMethod}
     * 
     * @return {@link Collection}
     */
    Collection<? extends FastMethod> getMethods();

    /**
     * Procura um {@link FastMethod}
     * 
     * @param name o nome
     * @param types os tipos
     * @return {@link FastMethod}
     */
    FastMethod findMethod(String name, Class<?>... types);

    /**
     * Procura um {@link FastMethod}
     * 
     * @param method {@link Method}
     * @return {@link FastMethod}
     */
    FastMethod findMethodFor(Method method);

    /**
     * Procura o melhor metodo a ser invocado com os parametros passados, devolvendo <code>null</code> caso contrario
     * 
     * @param methodName o nome do metodo
     * @param params os parametros
     * @return {@link FastMethod}
     * @see #findMethodBestMatch(String, Class[])
     */
    FastMethod findBestMethodFor(String methodName, Object... params);

    /**
     * Faz uma invocacao "dinamica", invocando o metodo com o nome passado cujos parametros mais se aproximam dos parametros passados, de
     * acordo com o metodo {@link #findBestMethodFor(String, Object...)}
     * 
     * @param methodName o nome do metodo
     * @param target o alvo da invocacao
     * @param params os parametros
     * @return Object
     * @throws NoSuchMethodException se nenhum metodo for encontrado
     * @throws Exception se o metodo lancar uma excecao
     * @see #findBestMethodFor(String, Object...)
     * @see #findMethodBestMatch(String, Class[])
     */
    Object invokeDynamic(String methodName, Object target, Object... params) throws NoSuchMethodException, Exception;

    /**
     * Procura o melhor metodo a ser invocado, de acordo com as regras do java para resolucao de metodos durante a compilacao, com a adicao
     * de regras de 'box' e 'unbox' de primitivas
     * 
     * @param methodName o nome do metodo
     * @param params os tipos dos parametros
     * @return {@link FastMethod} ou <code>null</code> se nenhum for encontrado
     */
    FastMethod findMethodBestMatch(String methodName, Class<?>[] params);

}
